/**
 * @file GMesh.h
 * @brief Gmsh类是用来提取Gmsh网格文件中的网格信息
 * @author YoHen-Fu <alittlefu@163.com>
 * @date 2024-03-25
*/
#pragma once

#include <fstream>
#include <string>
#include <vector>
#include <sstream>

/**
 * @brief 定义了一些基本的数据类型
*/
typedef unsigned int uint;

/**
 * @brief Gmsh类是用来提取Gmsh网格文件中的网格信息
 * @details 提供了读取Gmsh网格文件的接口
 * @details 网格信息包括节点坐标、单元信息、边界信息等
 * @details 网格文件格式参考：支持二维三角形单元以及三维四面体单元
 * @details 网格文件格式参考：https://gmsh.info/doc/texinfo/gmsh.html#MSH-file-format
*/
class GMesh{  // Gmsh类是用来提取Gmsh网格文件中的网格信息
private:
    uint numEntityBlocks, numNodes, minNodeTag, maxNodeTag;
    uint entityDim, entityTag, parametric, numNodesInBlock;
    uint numElements, minElementTag, maxElementTag;
    uint elementType, numElementsInBlock;
    std::vector<uint> selectedNodes, selectedElements;
    std::vector<std::vector<double>> coord{};
    std::vector<std::vector<uint>> element_P{};
    std::vector<std::vector<uint>> element_L{};
    std::vector<std::vector<uint>> element_S{};
    std::vector<std::vector<uint>> element_V{};
public:
    /**
     * @brief 构造函数
     *   
     * 构造函数，将类成员变量初始化为默认值
    */
    GMesh();
    /**
     * @brief 析构函数  
     * 
     * 析构函数默认不做任何事情
    */
    ~GMesh(){}
    /**
     * @brief 读取Gmsh网格文件 
     *  
     * 读取Gmsh网格文件，并提取网格信息
     * @param filename 网格文件名称
    */
    void getMesh(std::string filename);
    /**
     * @brief 清除网格信息  
     * 
     * 清除网格信息，将类成员变量初始化为默认值
    */
    void clearMesh();
    /**
     * @brief 获取网格结点坐标信息  
     * 
     * 获取结点编号以及对应的坐标信息
     * @return 二维矩阵，每一行代表一个结点的坐标信息。总列数为4，第1列为结点全局编号，后3列分别为x、y、z坐标
    */
    std::vector<std::vector<double>> getcoord() const { return coord; }
    /**
     * @brief 获取网格点单元点集信息  
     * 
     * 获取网格信息中的点单元编号以及对应的全局结点编号
     * @return 二维矩阵，每一行代表一个点单元的结点编号。总列数为3，第1列为点集组编号，
     * 第2列为点单元局部编号，第3列为点单元对应的全局编号
    */
    std::vector<std::vector<uint>> getelement_P() const { return element_P; }
    /**
     * @brief 获取网格线单元信息  
     * 
     * 获取网格信息中的线单元编号以及对应的全局结点编号
     * @return 二维矩阵，每一行代表一个线单元的结点编号。总列数为4，第1列为线集组编号，
     * 第2列为线单元局部编号，第3列到第4列为线单元对应的全局结点编号
    */
    std::vector<std::vector<uint>> getelement_L() const { return element_L; }
    /**
     * @brief 获取网格面单元信息  
     * 
     * 获取网格信息中的面单元编号以及对应的全局结点编号
     * @return 二维矩阵，每一行代表一个面单元的结点编号。总列数为5，第1列为面集组编号，
     * 第2列为面单元局部编号，第3列到第5列为面单元对应的全局结点编号
    */
    std::vector<std::vector<uint>> getelement_S() const { return element_S; }
    /**
     * @brief 获取网格体单元信息  
     * 
     * 获取网格信息中的体单元编号以及对应的全局结点编号
     * @return 二维矩阵，每一行代表一个体单元的结点编号。总列数为6，第1列为体集组编号，
     * 第2列为体单元局部编号，第3列到第6列为体单元对应的全局结点编号
    */
    std::vector<std::vector<uint>> getelement_V() const { return element_V; }
    /**
     * @brief 获取网格结点数量  
     * 
     * 获取网格中结点的数量
     * @return 结点数量
    */
    uint getnumNodes() const { return numNodes; }
    /**
     * @brief 获取网格单元数量  
     * 
     * 获取网格中单元的数量
     * @return 单元数量
    */
    uint getnumElements() const { return numElements; }
    /**
     * @brief 设置选中的结点编号  
     * 
     * 设置选中的结点编号
    */
    void setselectedNodes(std::vector<uint> selectedNodes) { this->selectedNodes = selectedNodes; }
    /**
     * @brief 设置选中的单元编号  
     * 
     * 设置选中的单元编号
    */
    void setselectedElements(std::vector<uint> selectedElements) { this->selectedElements = selectedElements; }
    /**
     * @brief 获取选中的结点编号  
     * 
     * 获取选中的结点编号
     * @return 选中的结点编号
    */
    std::vector<uint> getselectedNodes() const { return selectedNodes; }
    /**
     * @brief 获取选中的单元编号  
     * 
     * 获取选中的单元编号
     * @return 选中的单元编号 
    */
    std::vector<uint> getselectedElements() const { return selectedElements; }
};